package de.akabahn.ebd.stw.zdxfc.prs.elemente;

import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT0;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT2;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.GLEISFREIMELDUNG_FREI;

import org.apache.log4j.Logger;

import de.akabahn.ebd.comm.dbd.DBDParameter;
import de.akabahn.ebd.stw.zdxfc.prs.ZDXFCMain;

/**
 * Implementierung des Fahrwegelements <code>Gleis</code>.<br>
 * <br>
 * Bitcodierung der Gleismelder<br>
 * <pre>
 * BIT3 BIT2 BIT1 BIT0  BEDEUTUNG
 *    0    0    0    0  AUS
 *    0    0    0    1  WEISS AN
 *    0    0    1    0  WEISS BLINKT
 *    0    1    0    0  ROT AN
 *    1    0    0    0  ROT BLINKT
 * </pre>
 *    
 * @author Peter Eimann
 * @since 1.0
 * @version 1.2
 */
public class Gleis extends FahrwegElement {

	private final static Logger LOG = Logger.getLogger(Gleis.class);
	
	private boolean besetzt;
	private String gleisMelder;
	private boolean zeigeGleisMelder;
	
	/**
	 * Initialisierung der Klasse
	 * 
	 * @param id
	 *            Eindeutige ID des Elements, wird fuer die Referenz auf das
	 *            Element benoetigt (die ID ist der Schluessel in den Maps, in
	 *            denen das Element gespeichert ist.
	 * @param gleisMelder
	 *            Name der DBD-Variablen fuer den dem Gleis zugeordneten
	 *            Gleismelder im TCO
	 * @param main
	 *            Referenz auf die Hauptklasse
	 */
	public Gleis(String id, String gleisMelder, ZDXFCMain main) {
		super(id, main);
		this.gleisMelder = gleisMelder;
	}

	/**
	 * Gibt zurueck, ob das Gleis besetzt ist oder nicht
	 * 
	 * @return <code>true</code> - Gleis ist besetzt
	 */
	public boolean isBesetzt() {
		return besetzt;
	}

	/**
	 * Setzt das Besetzt-Flag fuer das Gleis
	 * 
	 * @param besetzt Das Besetzt-Flag
	 */
	public void setBesetzt(boolean besetzt) {
		this.besetzt = besetzt;
		LOG.info(id + ": Besetzt = " + besetzt);
	}

	/**
	 * Schaltet das <code>zeigeGleisMelder</code> Flag ein oder aus, wenn die Taste <code>Test Zones</code> auf dem
	 * Bedienpult gedrueckt oder losgelassen wird, anschliessend wird <code>gleisMelderAusleuchtung()</code> aufgerufen.
	 * 
	 * @see #gleisMelderAusleuchtung()
	 */
	public void setZeigeGleisMelder(boolean zeigeGleisMelder) {
		this.zeigeGleisMelder = zeigeGleisMelder;
		gleisMelderAusleuchtung();
		LOG.info(id + ": Zeige Gleismelder = " + this.zeigeGleisMelder);
	}

	/**
	 * Setzt das Aktiv-Flag des Elements<br>
	 * 
	 * @param aktiv Das Aktiv-Flag
	 * @see #gleisMelderAusleuchtung()
	 */
	@Override
	public void setAktiv(boolean aktiv) {
		super.setAktiv(aktiv);
		gleisMelderAusleuchtung();
	}

	/**
	 * Setzt das Besetzt-Flag des Gleises, wenn der Name der geaenderten Variablen mit <code>B</code> endet (fuer die
	 * Besetztinformation)
	 * 
	 * @param dbd Die geaenderte Variable, ID des Namens muss mit der ID des Elements uebereinstimmen
	 * @see #gleisMelderAusleuchtung()
	 */
	@Override
	public void onChangeProcess(DBDParameter dbd) {
		if (dbd.getId().equals(id) && (dbd.getName().endsWith("B"))) {
			setBesetzt(dbd.getValue() != GLEISFREIMELDUNG_FREI);
			gleisMelderAusleuchtung();
		}
	}

	/**
	 * Ausgabe des Zustands des Gleises
	 */
	public String toString() {
		return id + ": BES[" + besetzt + "] AKT[" + isAktiv() + "]";
	}
	
	/**
	 * Steuert die Ausleuchtung des Gleismelders im TCO.<br>
	 * <ul>
	 * <li>Gleis ist besetzt (aktiv oder nicht aktiv): Rote Ausleuchtung</li>
	 * <li>Gleis ist aktiv (und nicht besetzt) oder Ausleuchtung ist eingeschaltet: Weisse Ausleuchtung</li>
	 * <li>Gleis ist frei und nicht aktiv: Keine Ausleuchtung</li>
	 * </ul>
	 */
	private void gleisMelderAusleuchtung() {
		if (isBesetzt()) {
			main.getDbd().set(gleisMelder, BIT2);
		} else if (isAktiv() || zeigeGleisMelder) {
			main.getDbd().set(gleisMelder, BIT0);
		} else {
			main.getDbd().set(gleisMelder, 0);
		}
	}
}
